package com.liuhouse.config;

import com.liuhouse.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
//开启权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
//WebSecurityConfigurerAdapter是Security官方提供的类
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    //注入我们在liuhouse-blog工程写的jwtAuthenticationTokenFilter过滤器
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    //注入官方认证失败的处理器,注意不用写private,并且不是注入我们自定义的认证失败处理器，理由:符合开闭原则
    //虽然我们注入的不是自己写的认证失败处理器,但是最终用的实际上也是我们写的,Security会自己去找
    AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    //注入官方授权失败的处理器
    //注意不用写private,并且不是注入我们自定义的授权处理器，理由:符合开闭原则
    //虽然我们注入的不是自己写的授权失败处理器,但是最终用的实际上就是我们写的,Security会自己去找
    AccessDeniedHandler accessDeniedHandler;

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //把官方的PasswordEncoder密码加密方式替换成BCryptPasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //关闭csrf
                .csrf().disable()
                //不通过Session获取SecurityConetext
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                //对于登录接口,允许匿名访问
                .antMatchers("/user/login").anonymous()
                //由于刚开始博客后台模块,还没有登录,权限认证的功能,所以下载乃复制过来后,把下面的全部注释掉
                //对于登录接口,允许匿名访问
//                .antMatchers("/login").anonymous()
//                //需要登录才能在评论区发送评论
//                .antMatchers("/comment").authenticated()
//                //个人信息接口需要设置为登录才能访问，然后我们去访问的时候就能测试登录功能了
//                .antMatchers("/user/userInfo").authenticated()
                //把文件上传的接口设置为需要登录才能访问
//                .antMatchers("/upload").authenticated()
                //为了方便测试认证过滤器,我们把查询友情链接的接口设置为登录才能访问,然后我们去访问的时候就能测试登录认证功能了
//                .antMatchers("/link/getAllLink").authenticated() 其实友情链接是不需要进行登录验证的  而前端代码本身也没有传递token
                //退出登录的配置,如果没有登录就调用退出登录,就会报错,报的错设置为401,需要登录后操作,也就是authenticated
//                .antMatchers("/logout").authenticated()
                //除上面外所有的请求全部不需要认证即可访问

                //全部都需要认证才能访问
                .anyRequest().authenticated();

        //把我们自己写的自定义异常处理配置给Security
        http.exceptionHandling()
                        .authenticationEntryPoint(authenticationEntryPoint)
                        .accessDeniedHandler(accessDeniedHandler);

        http.logout().disable();

        //把我们在liuhouse-blog工程写的jwtAuthenticationTokenFilter过滤器添加到Security的过滤器链中
        //第一个参数是你要添加的过滤器,第二个参数是你想把你的过滤器添加到哪个security官方过滤器之前
        http.addFilterBefore(jwtAuthenticationTokenFilter , UsernamePasswordAuthenticationFilter.class);
        //允许跨域
        http.cors();
    }
}
